home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Utilities / Programming / EnterAct 3.5 / hAWK project / AWK Source / hAWK_FilesandClip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-08  |  18.4 KB  |  737 lines  |  [TEXT/KEEN]

  1. /* hAWK_FilesandClip.c : finally, some file manipulation routines for hAWK.
  2. Where a file or directory name is needed, they must be full pathnames
  3. in order to give predictable results.
  4. copy : copy a file from one location to another, optionally changing name.
  5. list : given file or directory full pathname, returns array of full pathnames
  6.     for all TEXT files in the directory. Note subdirectories are also excluded.
  7. nested : given file full pathname, returns array of full pathnames for
  8.     directories at the same level ("sibling folders"); given directory
  9.     name, returns array of subdirectories. In other words, the same as
  10.     list but for folders rather than files.
  11. remove : deletes a file
  12. rename : renames a file (without changing location). Note the old name
  13.     must be a full pathname, but the new name can be either a full pathname
  14.     or just a file name proper (no colons).
  15. exists : returns 1 if file exists, 0 if not
  16. fdate : returns date/time of last modification, format
  17.             yr:mo:day:hr:min:sec where yr is 4 digits, and the
  18.             rest are 2 (eg always 01 rather than just 1)
  19. fsize : returns size in bytes of file's data fork
  20. getclip : returns current calling app's clipboard text, as a string
  21.     (optional argument to specify max bytes of text retrieved)
  22. putclip : puts a string on the calling app's private clipboard
  23. beep : does a SysBeep(); if the duration you pass is <= 0, the
  24.     menu bar will flash instead of a beep
  25. */
  26. #include "AWK.H"
  27. #include <Files.h>
  28. extern void assoc_clear(NODE *symbol); /* ARRAY.C */
  29.  
  30.  
  31. /* Functions defined in this file */
  32. short b_get_two(NODE *tree, NODE **res1, NODE **res2);
  33. short c_get_two(NODE *tree, NODE **res1, NODE **res2);
  34. NODE *do_copy(NODE *tree);
  35. Boolean copy_file(Ptr oldNameP, short oldNmLen, Ptr newNameP, short newNmLen);
  36. OSErr CreateDirectories(StringPtr newName);
  37. NODE *do_list(NODE *tree);
  38. NODE *do_nested(NODE *tree);
  39. short list_files_or_dirs(char *theName, short nmlen, NODE *ind, Boolean dirs);
  40. NODE *do_rename(NODE *tree);
  41. Boolean _rename(Ptr oldNameP, short oldNmLen, Ptr newNameP, short newNmLen);
  42. NODE *do_remove(NODE *tree);
  43. Boolean _remove(char *name, short nmLen);
  44. NODE *do_exists(NODE *tree);
  45. Boolean _exists(char *name, short nmLen);
  46. NODE *do_fdate(NODE *tree);
  47. NODE *_fdate(char *name, short nmLen);
  48. NODE *do_fsize(NODE *tree);
  49. long _fsize(char *name, short nmLen);
  50. NODE *do_getclip(NODE *tree);
  51. NODE *_getclip(long maxBytes);
  52. NODE *do_putclip(NODE *tree);
  53. short _putclip(char *str);
  54. NODE *do_beep(NODE *tree);
  55.  
  56. short b_get_two(NODE *tree, NODE **res1, NODE **res2)
  57.     {
  58.     if (!tree)
  59.         return 0;
  60.     *res1 = tree_eval(tree->lnode);
  61.     if (!tree->rnode)
  62.         return 1;
  63.     tree = tree->rnode;
  64.     *res2 = tree->lnode;
  65.     return 2;
  66.     }
  67.  
  68.  
  69. short c_get_two(NODE *tree, NODE **res1, NODE **res2)
  70.     {
  71.     if (!tree)
  72.         return 0;
  73.     *res1 = tree_eval(tree->lnode);
  74.     if (!tree->rnode)
  75.         return 1;
  76.     tree = tree->rnode;
  77.     *res2 =  tree_eval(tree->lnode);
  78.     return 2;
  79.     }
  80. NODE *do_copy(NODE *tree)
  81.     {
  82.     NODE     *t1, *t2;    /* string, string */
  83.     NODE    *res;
  84.     char     *from, *to;
  85.     short        num_args;
  86.     
  87.     if ((num_args = c_get_two(tree, &t1, &t2)) < 2)
  88.         fatal("copy requires at least two arguments");
  89.     from = force_string(t1)->stptr;
  90.     to = force_string(t2)->stptr;
  91.     res =  tmp_number((AWKNUM)
  92.         copy_file(from, t1->stlen+1, to, t2->stlen+1));
  93.     free_temp(t1);
  94.     free_temp(t2);
  95.     return res;
  96.     }
  97.  
  98. /* Open & copy data forks, and resource forks. Use as big a buffer as you can get.
  99. Requires a non-empty data fork in original file. 
  100. Preserves type and creator.*/
  101. Boolean copy_file(Ptr oldNameP, short oldNmLen, Ptr newNameP, short newNmLen)
  102.     {
  103.     IOParam     pb, pbOut;
  104.     FileParam    fpb;
  105.     long        eof, count, bufSize, minBuf, numLeft, theType, theCreator;
  106.     Handle         hData;
  107.     char        oldName[256], newName[256];
  108.     OSErr         IOResult;
  109.     short            i;
  110. #define FileError(x)
  111.  
  112.     BlockMove(oldNameP, oldName, oldNmLen);
  113.     CtoPstr(oldName);
  114.     fpb.ioNamePtr = (StringPtr) oldName;
  115.     fpb.ioVRefNum = 0;
  116.     fpb.ioFVersNum = 0;
  117.     fpb.ioFDirIndex = 0;
  118.     if (PBGetFInfoSync((ParmBlkPtr)&fpb) != noErr)
  119.         return(FALSE);
  120.     theType = fpb.ioFlFndrInfo.fdType;
  121.     theCreator = fpb.ioFlFndrInfo.fdCreator;
  122.     
  123.     BlockMove(oldNameP, oldName, oldNmLen);
  124.     CtoPstr(oldName);
  125.     BlockMove(newNameP, newName, newNmLen);
  126.     CtoPstr(newName);
  127.     
  128.     for (i = 0; i <= 1; ++i) /* 0 == data, 1 == resource fork */
  129.         {
  130.         numLeft = 0;
  131.         hData = NULL;
  132.         /* Set up the param block to read in the old fork. */
  133.         pb.ioCompletion = NULL;
  134.         pb.ioNamePtr = (StringPtr)oldName;
  135.         pb.ioVRefNum = 0;
  136.         pb.ioVersNum = 0;
  137.         pb.ioPermssn = fsRdPerm;
  138.         pb.ioMisc = NULL;
  139.         if (i == 0)
  140.             {
  141.             if (PBOpen((ParmBlkPtr)&pb, FALSE))
  142.                 { FileError(pb.ioResult); return(FALSE); }
  143.             }
  144.         else
  145.             {
  146.             if (PBOpenRF((ParmBlkPtr)&pb, FALSE)) /* missing resource fork is not an error */
  147.                 return(TRUE);
  148.             }
  149.         GetEOF(pb.ioRefNum, &eof);
  150.         if (!eof && i) /* empty resource fork - OK */
  151.             {
  152.             PBClose((ParmBlkPtr)&pb, FALSE);
  153.             return(TRUE);
  154.             }
  155.         bufSize = eof;
  156.         minBuf = 1024L;
  157.         if (minBuf > eof)
  158.             minBuf = 128L;
  159.         hData = NewHandle(bufSize);
  160.         while (MemError() != noErr)
  161.             {
  162.             bufSize /= 2L;
  163.             if (bufSize < minBuf)
  164.                 { /*DoMemoryAlert(fileErrMsg, minBuf);*/ goto Abort; }
  165.             hData = NewHandle(bufSize);
  166.             }
  167.         /* delete, create and open new file, allocating space on disk */
  168.         if (i == 0)
  169.             {
  170.             FSDelete((StringPtr)newName, 0); // ignore any error
  171.             if (IOResult = Create((StringPtr)newName, 0, theCreator, theType))
  172.                 {
  173.                 if (IOResult = CreateDirectories((StringPtr)newName)) // calls DirCreate repeatedly
  174.                     { FileError(IOResult); goto Abort; }
  175.                 // Try again with folders newly in place.
  176.                 if (IOResult = Create((StringPtr)newName, 0, theCreator, theType))
  177.                     { FileError(IOResult); goto Abort; }
  178.                 }
  179.             }
  180.         /* set up pbOut for the file with write permission and open the file */
  181.         pbOut.ioCompletion = NULL;
  182.         pbOut.ioNamePtr = (StringPtr)newName;
  183.         pbOut.ioVRefNum = 0;
  184.         pbOut.ioVersNum = 0;
  185.         pbOut.ioPermssn = fsWrPerm;
  186.         pbOut.ioMisc = NULL;
  187.         if (i == 0)
  188.             {
  189.             if (PBOpen((ParmBlkPtr)&pbOut, FALSE))
  190.                 { FileError(pbOut.ioResult); goto Abort; }
  191.             }
  192.         else
  193.             {
  194.             if (PBOpenRF((ParmBlkPtr)&pbOut, FALSE))
  195.                 { FileError(pbOut.ioResult); goto Abort; }
  196.             }
  197.         pbOut.ioMisc = (Ptr)eof;
  198.         if (PBSetEOF((ParmBlkPtr)&pbOut, FALSE))
  199.             { FileError(pbOut.ioResult); goto Abort; }
  200.         /* set file marks to beginning of file */
  201.         pb.ioMisc = NULL;
  202.         pb.ioPosMode = fsFromStart;
  203.         pb.ioPosOffset = 0L;
  204.         if (PBSetFPos((ParmBlkPtr)&pb, FALSE))
  205.             { FileError(pb.ioResult); goto Abort; }
  206.         pbOut.ioMisc = NULL;
  207.         pbOut.ioPosMode = fsFromStart;
  208.         pbOut.ioPosOffset = 0L;
  209.         if (PBSetFPos((ParmBlkPtr)&pbOut, FALSE))
  210.             { FileError(pbOut.ioResult); goto Abort; }
  211.         /* r/w until done */
  212.         pb.ioBuffer = pbOut.ioBuffer = *hData; /* note no need to lock it */
  213.         numLeft = eof;
  214.         if (numLeft >= bufSize)
  215.             pb.ioReqCount = pbOut.ioReqCount = bufSize;
  216.         else
  217.             pb.ioReqCount = pbOut.ioReqCount = numLeft;
  218.         while (numLeft > 0)
  219.             {
  220.             if (numLeft < bufSize)
  221.                 pb.ioReqCount = pbOut.ioReqCount = numLeft;
  222.             if (PBRead((ParmBlkPtr)&pb, FALSE))
  223.                 { FileError(pb.ioResult); goto Abort; }
  224.             if (PBWrite((ParmBlkPtr)&pbOut, FALSE))
  225.                 { FileError(pbOut.ioResult); goto Abort; }
  226.             if (pb.ioActCount != pbOut.ioActCount)
  227.                 {
  228.                 /* if not for hAWK, notify user... */
  229.                 goto Abort;
  230.                 }
  231.             numLeft -= pb.ioActCount;
  232.             }
  233.  
  234.         if (PBClose((ParmBlkPtr)&pb, FALSE))
  235.             { FileError(pb.ioResult); goto Abort; }
  236.         if (PBClose((ParmBlkPtr)&pbOut, FALSE))
  237.             { FileError(pbOut.ioResult); goto Abort; }
  238.         DisposHandle(hData);
  239.         }
  240.     return(TRUE);
  241.  
  242. Abort:
  243.     if (hData)
  244.         DisposHandle(hData);
  245.     FSClose (pb.ioRefNum);
  246.     FSClose (pbOut.ioRefNum);
  247.     FSDelete((StringPtr)newName, 0);
  248.     return(FALSE);
  249. #undef FileError
  250.     }
  251.  
  252. // Attempt to create directories along the newName proposed path.
  253. // We start at the root, for want of a better place.
  254. // A full path name is more or less assumed.
  255. OSErr CreateDirectories(StringPtr newName)
  256.     {
  257.     OSErr    io;
  258.     long    parentDirID, createdDirID;
  259.     short    reallyTrueLen, trueLen, currentLen;
  260.     
  261.     if (newName[1] == ':')     // not a full path name
  262.         return bdNamErr;
  263.     // trim file name from path
  264.     reallyTrueLen = trueLen = newName[0];
  265.     while (newName[trueLen] != ':' && trueLen > 0)
  266.         --trueLen;
  267.     if (trueLen <= 4)        // minimum is a:b:c
  268.         return bdNamErr;
  269.     currentLen = 2;
  270.     // skip to a colon
  271.     while (newName[currentLen] != ':' && currentLen < trueLen)
  272.         ++currentLen;
  273.     if (newName[currentLen] != ':' || currentLen >= trueLen)
  274.         return bdNamErr;
  275.     // and skip to another colon
  276.     ++currentLen;
  277.     while (currentLen <= trueLen && newName[currentLen] != ':')
  278.         ++currentLen;
  279.     if (currentLen >= trueLen)
  280.         return bdNamErr;
  281.                 
  282.     newName[0] = currentLen; // we start with the volume name and first dir...
  283.     parentDirID = 2;            // ...which should be at the root directory
  284.     do
  285.         {
  286.         io = DirCreate(0, parentDirID, newName, &createdDirID);
  287.         // Continue while directory exists or can be created.
  288.         if (io == noErr || io == dupFNErr)
  289.             {
  290.             ++currentLen;
  291.             while (currentLen <= trueLen && newName[currentLen] != ':')
  292.                 ++currentLen;
  293.             if (currentLen > trueLen)
  294.                 break;
  295.             newName[0] = currentLen;
  296.             parentDirID = createdDirID;
  297.             }
  298.         } while (io == noErr || io == dupFNErr);
  299.     newName[0] = reallyTrueLen; // or else!
  300.     return io; // Note even dupFNErr counts as an error at the end.
  301.     }
  302.  
  303. /* Expect file or dir name, followed by array to place list. Return
  304. number of files in directory. */
  305. NODE *do_list(NODE *tree)
  306.     {
  307.     NODE     *t1, *t2;
  308.     NODE     *ind;
  309.     NODE    *res;
  310.     char    *name;
  311.     short        num_args;
  312.     
  313.     if ((num_args = b_get_two(tree, &t1, &t2)) < 2)
  314.         fatal("list requires at least two arguments");
  315.     name = force_string(t1)->stptr;
  316.     ind = t2;
  317.     if (t2->type == Node_param_list)
  318.         ind = stack_ptr[t2->param_cnt];
  319.     if (ind->type != Node_var && ind->type != Node_var_array)
  320.         fatal("second argument of list is not a variable");
  321.     assoc_clear(ind);
  322.     res = tmp_number((AWKNUM)list_files_or_dirs(name, t1->stlen+1, ind, FALSE));
  323.     free_temp(t1);
  324.     return res;
  325.     }
  326.  
  327. NODE *do_nested(NODE *tree)
  328.     {
  329.     NODE     *t1, *t2;
  330.     NODE     *ind;
  331.     NODE    *res;
  332.     char    *name;
  333.     short        num_args;
  334.     
  335.     if ((num_args = b_get_two(tree, &t1, &t2)) < 2)
  336.         fatal("nested requires at least two arguments");
  337.     name = force_string(t1)->stptr;
  338.     ind = t2;
  339.     if (t2->type == Node_param_list)
  340.         ind = stack_ptr[t2->param_cnt];
  341.     if (ind->type != Node_var && ind->type != Node_var_array)
  342.         fatal("second argument of nested is not a variable");
  343.     assoc_clear(ind);
  344.     res = tmp_number((AWKNUM)list_files_or_dirs(name, t1->stlen+1, ind, TRUE));
  345.     free_temp(t1);
  346.     return res;
  347.     }
  348.  
  349. /* Given full path name, index thru a directory via PBGetCatInfo.
  350. Return number of files/dirs. Create list of TEXT file names
  351. or directory names in array "ind", indexed 1..numFiles.
  352. */
  353. short list_files_or_dirs(char *theName, short nmlen, NODE *ind, Boolean dirs)
  354.     {
  355.     HVolumeParam    vParms;
  356.     CInfoPBPtr     cipbr = (CInfoPBPtr)&vParms;
  357.     HFileInfo    *fpb = (HFileInfo *)&vParms;
  358.     DirInfo        *dpb = (DirInfo *)&vParms;
  359.     WDPBRec        theParms;
  360.     char        fName[256], volName[32], dirName[256]; /* dirName becomes full name */
  361.     long        dirID;
  362.     short        index = 1, numFiles = 0, strln, dirLen, i, theVolRef;
  363.     OSErr        err;
  364.     
  365.     BlockMove(theName, fName, nmlen);
  366.     CtoPstr(fName);
  367.     
  368.     fpb->ioNamePtr = (StringPtr)fName;
  369.     fpb->ioVRefNum = -32768;
  370.     fpb->ioFDirIndex = 0;
  371.     fpb->ioDirID = 0;
  372.     if (PBGetCatInfo(cipbr, FALSE))
  373.         return(0);
  374.     if (((fpb->ioFlAttrib>>4) & 0x01) != 1) /* a file */
  375.         {
  376.         dirID = fpb->ioFlParID;
  377.         strln = nmlen-1;
  378.         while (strln > 0 && *(theName + strln-1) != ':')
  379.             --strln;
  380.         if (strln <= 0) /* whole name was just a file name */
  381.             {
  382.             strln = 1;
  383.             dirName[0] = ':';
  384.             dirName[1] = '\0';
  385.             }
  386.         else
  387.             {
  388.             BlockMove(theName, dirName, strln);
  389.             dirName[strln] = '\0';
  390.             }
  391.         }
  392.     else /* we were given a directory */
  393.         {
  394.         dirID = dpb->ioDrDirID;
  395.         strln =  nmlen-1;
  396.         BlockMove(theName, dirName, strln);
  397.         if (*(theName + strln-1) != ':')
  398.             dirName[strln++] = ':';
  399.         dirName[strln] = '\0';
  400.         }
  401.     dirLen = strln;
  402.     
  403.     /* open working directory */
  404.     i = 0;
  405.     do
  406.         {
  407.         volName[i+1] = dirName[i];
  408.         } while (i < 30 && dirName[i++] != ':');
  409.     volName[0] = i;
  410.     vParms.ioNamePtr = (StringPtr)(volName);
  411.     vParms.ioVRefNum = -32768;
  412.     vParms.ioVolIndex = -1;
  413.     if (PBHGetVInfo((HParmBlkPtr)&vParms, FALSE))
  414.         theParms.ioVRefNum = 0;
  415.     else
  416.         theParms.ioVRefNum = vParms.ioVRefNum;
  417.     
  418.     theParms.ioNamePtr = NULL;
  419.     theParms.ioWDDirID = dirID;
  420.     theParms.ioWDProcID = 'ERIK';
  421.     if (PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  422.         theParms.ioVRefNum = 0;
  423.     theParms.ioNamePtr = NULL;
  424.     theParms.ioWDIndex = 0;
  425.     theParms.ioWDProcID = 0;
  426.     theParms.ioWDVRefNum = 0;
  427.     if (PBGetWDInfo(&theParms,false))
  428.         return(0);
  429.     fpb->ioVRefNum = theParms.ioWDVRefNum;
  430.     fpb->ioNamePtr = (StringPtr)fName;
  431.     do
  432.         {
  433.         fpb->ioFDirIndex = index;
  434.         fpb->ioDirID = dirID;
  435.         if ((err = PBGetCatInfo(cipbr, FALSE)) == noErr)
  436.             {
  437.             if (!dirs && !(fpb->ioFlAttrib & 16)) /* a file */
  438.                 {
  439.                 /* Is it the right kind of file? */
  440.                 if (fpb->ioFlFndrInfo.fdType == 'TEXT')
  441.                     {
  442.                     ++numFiles;
  443.                     strln = fName[0] + dirLen;
  444.                     PtoCstr((unsigned char *)fName);
  445.                     dirName[dirLen] = '\0';
  446.                     strcat(dirName, fName);
  447.                     *assoc_lookup(ind, tmp_number((AWKNUM) (numFiles))) 
  448.                         = make_string(dirName, strln);
  449.                     }
  450.                 }
  451.             else if (dirs && (fpb->ioFlAttrib & 16)) /* a directory */
  452.                 {
  453.                 ++numFiles;
  454.                 strln = fName[0] + dirLen;
  455.                 PtoCstr((unsigned char *)fName);
  456.                 dirName[dirLen] = '\0';
  457.                 strcat(dirName, fName);
  458.                 *assoc_lookup(ind, tmp_number((AWKNUM) (numFiles))) 
  459.                     = make_string(dirName, strln);
  460.                 }
  461.             }
  462.         ++index;
  463.         } while (err == noErr);
  464.     return(numFiles);
  465.     }
  466.  
  467. NODE *do_rename(NODE *tree)
  468.     {
  469.     NODE     *t1, *t2;    /* string, string */
  470.     NODE    *res;
  471.     char     *from, *to;
  472.     short        num_args;
  473.     
  474.     if ((num_args = c_get_two(tree, &t1, &t2)) < 2)
  475.         fatal("rename requires at least two arguments");
  476.     from = force_string(t1)->stptr;
  477.     to = force_string(t2)->stptr;
  478.     res =  tmp_number((AWKNUM)
  479.         _rename(from, t1->stlen+1, to, t2->stlen+1));
  480.     free_temp(t1);
  481.     free_temp(t2);
  482.     return res;
  483.     }
  484.  
  485. /* Rename a file. Rename of volumes is not allowed. Location cannot
  486. be changed with this function. If only a new file name is supplied,
  487. fill in its full path from the old full pathname. */
  488. Boolean _rename(Ptr oldNameP, short oldNmLen, Ptr newNameP, short newNmLen)
  489.     {
  490.     char    oldName[256], newName[256];
  491.     Ptr        tPtr, endPtr;
  492.     Boolean    hasColons = FALSE;
  493.     
  494.     if (oldNmLen <= 2 || *(oldNameP + oldNmLen - 2) == ':')
  495.         return(FALSE);
  496.     /* if new name is just a file name, fill in the full path from
  497.     the old name */
  498.     tPtr = newNameP;
  499.     endPtr = newNameP + newNmLen - 1;
  500.     while (tPtr < endPtr)
  501.         {
  502.         if (*tPtr++ == ':')
  503.             {
  504.             hasColons = TRUE;
  505.             break;
  506.             }
  507.         }
  508.     if (!hasColons)
  509.         {
  510.         endPtr = oldNameP + oldNmLen - 2;
  511.         tPtr = oldNameP;
  512.         while (endPtr > tPtr && *(endPtr-1) != ':')
  513.             --endPtr;
  514.         if (endPtr == oldNameP + oldNmLen - 2
  515.             || endPtr < tPtr + 2)
  516.             return(FALSE);
  517.         if (newNmLen + (endPtr - tPtr) > 255)
  518.             return(FALSE);
  519.         BlockMove(newNameP, newName+(endPtr-tPtr), newNmLen);
  520.         BlockMove(tPtr, newName, endPtr-tPtr);
  521.         }
  522.     else
  523.         BlockMove(newNameP, newName, newNmLen);
  524.     BlockMove(oldNameP, oldName, oldNmLen);
  525.     CtoPstr(oldName);
  526.     CtoPstr(newName);
  527.     return(Rename((StringPtr)oldName,0,(StringPtr)newName) == noErr);
  528.     }
  529.  
  530. NODE *do_remove(NODE *tree)
  531.     {
  532.     NODE     *t1, *t2;
  533.     
  534.     if (!tree)
  535.         return tmp_number((AWKNUM)0);
  536.     t1 = force_string(tree_eval(tree->lnode));
  537.     t2 =  tmp_number((AWKNUM)_remove(t1->stptr, t1->stlen+1));
  538.     free_temp(t1);
  539.     return t2;
  540.     }
  541.  
  542. Boolean _remove(char *name, short nmLen)
  543.     {
  544.     FileParam    fpb;
  545.     char        fName[256];
  546.     
  547.     BlockMove(name, fName, nmLen);
  548.     CtoPstr(fName);
  549.     fpb.ioNamePtr = (StringPtr) fName;
  550.     fpb.ioVRefNum = 0;
  551.     fpb.ioFVersNum = 0;
  552.     return(PBDelete((ParmBlkPtr)&fpb, FALSE) == noErr);
  553.     }
  554.  
  555. NODE *do_exists(NODE *tree)
  556.     {
  557.     NODE *t1, *t2;
  558.     
  559.     if (!tree)
  560.         return tmp_number((AWKNUM)0);
  561.     t1 = force_string(tree_eval(tree->lnode));
  562.     t2 =  tmp_number((AWKNUM)_exists(t1->stptr, t1->stlen+1));
  563.     free_temp(t1);
  564.     return t2;
  565.     }
  566.  
  567. Boolean _exists(char *name, short nmLen)
  568.     {
  569.     FileParam     pb;
  570.     char        fName[256];
  571.     
  572.     BlockMove(name, fName, nmLen);
  573.     CtoPstr(fName);
  574.     pb.ioNamePtr = (StringPtr) fName;
  575.     pb.ioVRefNum = 0;
  576.     pb.ioFVersNum = 0;
  577.     pb.ioFDirIndex = 0;
  578.     return(PBGetFInfoSync((ParmBlkPtr)&pb) == noErr);
  579.     }
  580.  
  581. NODE *do_fdate(NODE *tree)
  582.     {
  583.     NODE *t1, *r;
  584.     
  585.     if (!tree)
  586.         return Nnull_string;
  587.     t1 = force_string(tree_eval(tree->lnode));
  588.     r = _fdate(t1->stptr, t1->stlen+1);
  589.     free_temp(t1);
  590.     return r;
  591.     }
  592.  
  593. NODE *_fdate(char *name, short nmLen)
  594.     {
  595.     FileParam     pb;
  596.     DateTimeRec    dtr;
  597.     char        fName[256], when[32];
  598.     NODE        *r;
  599.     
  600.     BlockMove(name, fName, nmLen);
  601.     CtoPstr(fName);
  602.     pb.ioNamePtr = (StringPtr) fName;
  603.     pb.ioVRefNum = 0;
  604.     pb.ioFVersNum = 0;
  605.     pb.ioFDirIndex = 0;
  606.     if (PBGetFInfoSync((ParmBlkPtr)&pb) != noErr)
  607.         return Nnull_string;
  608.     Secs2Date(pb.ioFlMdDat, &dtr);
  609.     sprintf(when, "%.4d:%.2d:%.2d:%.2d:%.2d:%.2d", 
  610.             dtr.year, dtr.month, dtr.day,
  611.             dtr.hour, dtr.minute, dtr.second);
  612.     r = tmp_string(when, 19);
  613.     return r;
  614.     }
  615.  
  616. NODE *do_fsize(NODE *tree)
  617.     {
  618.     NODE     *t1, *t2;
  619.     
  620.     if (!tree)
  621.         return tmp_number((AWKNUM)0);
  622.     t1 = force_string(tree_eval(tree->lnode));
  623.     t2 =  tmp_number((AWKNUM)_fsize(t1->stptr, t1->stlen+1));
  624.     free_temp(t1);
  625.     return t2;
  626.     }
  627.  
  628. long _fsize(char *name, short nmLen)
  629.     {
  630.     FileParam     pb;
  631.     char        fName[256];
  632.     
  633.     BlockMove(name, fName, nmLen);
  634.     CtoPstr(fName);
  635.     pb.ioNamePtr = (StringPtr) fName;
  636.     pb.ioVRefNum = 0;
  637.     pb.ioFVersNum = 0;
  638.     pb.ioFDirIndex = 0;
  639.     if (PBGetFInfoSync((ParmBlkPtr)&pb) != noErr)
  640.         return(0L);
  641.     return(pb.ioFlLgLen);
  642.     }
  643.  
  644. NODE *do_getclip(NODE *tree)
  645.     {
  646.     NODE *t1;
  647.     long    maxBytes;
  648.     
  649.     if (!tree)
  650.         maxBytes = 0;
  651.     else
  652.         {
  653.         t1 = tree_eval(tree->lnode);
  654.         maxBytes = (long) force_number(t1);
  655.         free_temp(t1);
  656.         }
  657.     return _getclip(maxBytes);
  658.     }
  659.  
  660. NODE *_getclip(long maxBytes)
  661.     {
  662.     NODE         *t1;
  663.     Handle         hText;
  664.     long        clipSize;
  665.     extern Handle GetTheClip(void);
  666.     
  667.     hText = GetTheClip();
  668.     if (!hText)
  669.         return Nnull_string;
  670.     if (maxBytes < 0)
  671.         maxBytes = 0;
  672.     clipSize = GetHandleSize(hText);
  673.     if (!clipSize)
  674.         return Nnull_string;
  675.     if (maxBytes && clipSize > maxBytes)
  676.         clipSize = maxBytes;
  677.     // Revision, keep it short.
  678.     if (clipSize > 32766L)
  679.         clipSize = 32766L;
  680.     HLock(hText);
  681.     t1 = tmp_string(*hText, clipSize);
  682.     HUnlock(hText);
  683.     return t1;    
  684.     }
  685.  
  686. NODE *do_putclip(NODE *tree)
  687.     {
  688.     NODE *t1, *t2;
  689.     
  690.     if (!tree)
  691.         {
  692.         char c = 0;
  693.         t2 =  tmp_number((AWKNUM)_putclip(&c));
  694.         }
  695.     else
  696.         {
  697.         t1 = force_string(tree_eval(tree->lnode));
  698.         t2 =  tmp_number((AWKNUM)_putclip(t1->stptr));
  699.         free_temp(t1);
  700.         }
  701.     return t2;
  702.     }
  703.  
  704. short _putclip(char *str)
  705.     {
  706.     extern short PutTheClip(char *newClipStr);
  707.     
  708.     return PutTheClip(str);
  709.     }
  710.  
  711. NODE *do_beep(NODE *tree)
  712.     {
  713.     NODE *t1;
  714.     short duration, shortlevel;
  715.     
  716.     if (!tree)
  717.         duration = 2;
  718.     else
  719.         {
  720.         t1 = tree_eval(tree->lnode);
  721.         duration = (short) force_number(t1);
  722.         free_temp(t1);
  723.         }
  724.     if (duration < 0)
  725.         duration = 0;
  726.     if (!duration)
  727.         {
  728.         long finalTick;
  729.         FlashMenuBar(0);
  730.         Delay(2, &finalTick);
  731.         FlashMenuBar(0);
  732.         }
  733.     else
  734.         SysBeep(duration);
  735.     return Nnull_string;
  736.     }
  737.